{
  "cells": [
    {
      "cell_type": "raw",
      "metadata": {},
      "source": [
        "---\n",
        "title: Mojo language basics\n",
        "sidebar_label: Language basics\n",
        "description: A short introduction to the Mojo language basics.\n",
        "css: /static/styles/page-navigation.css\n",
        "aliases:\n",
        "  - /mojo/notebooks/HelloMojo.html\n",
        "website:\n",
        "  open-graph:\n",
        "    image: /static/images/mojo-social-card.png\n",
        "  twitter-card:\n",
        "    image: /static/images/mojo-social-card.png\n",
        "---"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "[//]: # REMOVE_FOR_WEBSITE\n",
        "*Copyright 2023 Modular, Inc: Licensed under the Apache License v2.0 with LLVM Exceptions.*"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "[//]: # REMOVE_FOR_WEBSITE\n",
        "# Mojo language basics"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Mojo is a powerful programming language that's primarily designed for\n",
        "high-performance systems programming, so it has a lot in common with other\n",
        "systems languages like Rust and C++. Yet, Mojo is also designed to become a\n",
        "superset of Python, so a lot of language features and concepts you might know\n",
        "from Python translate nicely to Mojo. \n",
        "\n",
        "For example, if you're in a REPL environment or Jupyter notebook (like this\n",
        "document), you can run top-level code just like Python:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Hello Mojo!\n"
          ]
        }
      ],
      "source": [
        "#| CHECK: Hello Mojo!\n",
        "print(\"Hello Mojo!\")"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "You don't normally see that with other systems programming languages.\n",
        "\n",
        "Mojo preserves Python's dynamic features and language syntax, and it even\n",
        "allows you to import and run code from Python packages. However, it's important\n",
        "to know that Mojo is an entirely new language, not just a new implementation of\n",
        "Python with syntax sugar. Mojo takes the Python language to a whole new level,\n",
        "with systems programming features, strong type-checking, memory safety,\n",
        "next-generation compiler technologies, and more. Yet, it's still designed to be\n",
        "a simple language that's useful for general-purpose programming.\n",
        "\n",
        "This page provides a gentle introduction to the Mojo language, and requires\n",
        "only a little programming experience. So let's get started!\n",
        "\n",
        "For more details about everything covered here, check out the\n",
        "[Mojo Manual](https://docs.modular.com/mojo/manual/)."
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Language basics\n",
        "\n",
        "First and foremost, Mojo is a compiled language and a lot of its performance\n",
        "and memory-safety features are derived from that fact. Mojo code can be\n",
        "ahead-of-time (AOT) or just-in-time (JIT) compiled.\n",
        "\n",
        "Like other compiled languages, Mojo programs (`.mojo` or `.🔥` files) require a\n",
        "`main()` function as the entry point to the program. For example:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "metadata": {},
      "outputs": [],
      "source": [
        "fn main():\n",
        "    var x: Int = 1\n",
        "    x += 1\n",
        "    print(x)"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "If you know Python, you might have expected the function name to be `def\n",
        "main()` instead of `fn main()`. Both actually work in Mojo, but using `fn`\n",
        "behaves a bit differently, as we'll discuss below.\n",
        "\n",
        "Of course, if you're building a Mojo module (an API library), not a Mojo\n",
        "program, then your file doesn't need a `main()` function (because it will be\n",
        "imported by other programs that do have one).\n",
        "\n",
        "<div class=\"alert alert-block alert-info alert--secondary\">\n",
        "\n",
        "**Note:** When you're writing code in a `.mojo`/`.🔥` file, you can't run\n",
        "top-level code as shown on this page—all code in a Mojo program or module\n",
        "must be encased in a function or struct. However, top-level code does work in a\n",
        "REPL or Jupyter notebook (such as the [notebook for this\n",
        "page](https://github.com/modularml/mojo/blob/main/examples/notebooks/HelloMojo.ipynb)).\n",
        "\n",
        "</div>\n",
        "\n",
        "Now let's explain the code in this `main()` function."
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### Syntax and semantics\n",
        "\n",
        "This is simple: Mojo supports (or will support) all of Python's syntax and\n",
        "semantics. If you're not familiar with Python syntax, there are a ton of great\n",
        "resources online that can teach you.\n",
        "\n",
        "For example, like Python, Mojo uses line breaks and indentation to define code\n",
        "blocks (not curly braces), and Mojo supports all of Python's control-flow syntax\n",
        "such as `if` conditions and `for` loops.\n",
        "\n",
        "However, Mojo is still a work in progress, so there are some things from Python\n",
        "that aren't implemented in Mojo yet (see the [Mojo\n",
        "roadmap](https://docs.modular.com/mojo/roadmap.html)). All the missing Python\n",
        "features will arrive in time, but Mojo already includes many features and\n",
        "capabilities beyond what's available in Python.\n",
        "\n",
        "As such, the following sections will focus on some of the language features that\n",
        "are unique to Mojo (compared to Python)."
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\n",
        "### Functions\n",
        "\n",
        "Mojo functions can be declared with either `fn` (shown above) or `def` (as\n",
        "in Python). The `fn` declaration enforces strongly-typed and memory-safe\n",
        "behaviors, while `def` provides Python-style dynamic behaviors.\n",
        "\n",
        "Both `fn` and `def` functions have their value, and it's important that you\n",
        "learn them both. However, for the purposes of this introduction, we're going to\n",
        "focus on `fn` functions only. For more detail about both, see the [functions\n",
        "page in the manual](https://docs.modular.com/mojo/manual/functions.html).\n",
        "\n",
        "In the following sections, you'll learn how `fn` functions enforce\n",
        "strongly-typed and memory-safe behaviors in your code."
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### Variables\n",
        "\n",
        "You can declare variables (such as `x` in the above `main()` function) with\n",
        "`var` to create a mutable value, or with `let` to create an immutable value.\n",
        "\n",
        "If you change `var` to `let` in the `main()` function above and run it, you'll\n",
        "get a compiler error like this:\n",
        "\n",
        "```text\n",
        "error: Expression [15]:7:5: expression must be mutable for in-place operator destination\n",
        "    x += 1\n",
        "    ^\n",
        "```\n",
        "\n",
        "That's because `let` makes the value immutable, so you can't increment it.\n",
        "\n",
        "And if you delete `var` completely, you'll get an error because `fn` functions\n",
        "require explicit variable declarations (unlike Python-style `def` functions).\n",
        "\n",
        "Finally, notice that the `x` variable has an explicit `Int` type specification.\n",
        "Declaring the type is not required for variables in `fn`, but it is desirable\n",
        "sometimes. If you omit it, Mojo infers the type, as shown here:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "3\n"
          ]
        }
      ],
      "source": [
        "fn do_math():\n",
        "    var x: Int = 1\n",
        "    var y = 2\n",
        "    print(x + y)\n",
        "\n",
        "do_math()"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### Function arguments and returns\n",
        "\n",
        "Although types aren't required for variables declared in the function body,\n",
        "they are required for arguments and return values for an `fn` function.\n",
        "\n",
        "For example, here's how to declare `Int` as the type for function arguments and\n",
        "the return value:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "3\n"
          ]
        }
      ],
      "source": [
        "fn add(x: Int, y: Int) -> Int:\n",
        "    return x + y\n",
        "\n",
        "z = add(1, 2)\n",
        "print(z)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "#### Optional arguments and keyword arguments\n",
        "\n",
        "You can also specify argument default values (also known as optional\n",
        "arguments), and pass values with keyword argument names. For example:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "9\n",
            "8\n"
          ]
        }
      ],
      "source": [
        "fn my_pow(base: Int, exp: Int = 2) -> Int:\n",
        "    return base ** exp\n",
        "\n",
        "# Uses default value for `exp`\n",
        "z = my_pow(3)\n",
        "print(z)\n",
        "\n",
        "# Uses keyword argument names (with order reversed)\n",
        "z = my_pow(exp=3, base=2)\n",
        "print(z)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\n",
        "<div class=\"alert alert-block alert-info alert--secondary\">\n",
        "\n",
        "**Note:** Mojo currently includes only partial support for keyword arguments, so\n",
        "some features such as keyword-only arguments and variadic keyword arguments (e.g. `**kwargs`)\n",
        "are not supported yet.\n",
        "\n",
        "</div>"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "#### Argument mutability and ownership\n",
        "\n",
        "Mojo supports full [value\n",
        "semantics](https://en.wikipedia.org/wiki/Value_semantics) and enforces memory\n",
        "safety with a robust value ownership model (similar to the Rust borrow\n",
        "checker). Essentially, that means Mojo allows you to share references to values\n",
        "(instead of making a copy every time you pass a value to a function), but doing\n",
        "so requires that you follow Mojo's ownership rules (to ensure memory safety) as\n",
        "described in this section.\n",
        "\n",
        "Notice that, above, `add()` doesn't modify `x` or `y`, it only reads the\n",
        "values. In fact, as written, the function *cannot* modify them because `fn`\n",
        "arguments are **immutable references** by default. This ensures memory safety\n",
        "(no surprise changes to the data) while also avoiding a copy (which could be\n",
        "a performance hit).\n",
        "\n",
        "In terms of argument conventions, this is called \"borrowing,\" and although it's\n",
        "the default for `fn` functions, you can make it explicit with the `borrowed`\n",
        "declaration like this (this behaves exactly the same as the `add()` above):"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "metadata": {},
      "outputs": [],
      "source": [
        "fn add(borrowed x: Int, borrowed y: Int) -> Int:\n",
        "    return x + y"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "If you want the arguments to be mutable, you need to declare each argument\n",
        "convention as `inout`. This means that changes made to the arguments *in*side\n",
        "the function are visible *out*side the function. \n",
        "\n",
        "For example, this function is able to modify the original variables:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "2\n",
            "3\n",
            "5\n"
          ]
        }
      ],
      "source": [
        "fn add_inout(inout x: Int, inout y: Int) -> Int:\n",
        "    x += 1\n",
        "    y += 1\n",
        "    return x + y\n",
        "\n",
        "var a = 1\n",
        "var b = 2\n",
        "c = add_inout(a, b)\n",
        "print(a)\n",
        "print(b)\n",
        "print(c)"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Another option is to declare the argument as `owned`, which provides\n",
        "the function full ownership of the value (it's mutable and guaranteed unique).\n",
        "This way, the function can modify the value and not worry about affecting\n",
        "variables outside the function. For example:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "mojo\n",
            "mojo🔥\n"
          ]
        }
      ],
      "source": [
        "fn set_fire(owned text: String) -> String:\n",
        "    text += \"🔥\"\n",
        "    return text\n",
        "\n",
        "fn mojo():\n",
        "    var a: String = \"mojo\"\n",
        "    var b = set_fire(a)\n",
        "    print(a)\n",
        "    print(b)\n",
        "\n",
        "mojo()"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "In this case, Mojo makes a copy of `a` and passes it as the `text` argument.\n",
        "The original `a` string is still alive and well.\n",
        "\n",
        "However, if you want to give the function ownership of the value and **do not**\n",
        "want to make a copy (which can be an expensive operation for some types), then\n",
        "you can add the `^` \"transfer\" operator when you pass `a` to the function. The\n",
        "transfer operator effectively destroys the local variable name—any attempt to\n",
        "call upon it later causes a compiler error.\n",
        "\n",
        "Try it above by changing the call to `set_fire()` to look like this:\n",
        "\n",
        "```mojo\n",
        "    var b = set_fire(a^)\n",
        "```\n",
        "\n",
        "You'll now get an error because the transfer operator effectively destroys the\n",
        "`a` variable, so when the following `print()` function tries to use `a`, that\n",
        "variable isn't initialized anymore.\n",
        "\n",
        "If you delete `print(a)`, then it works fine.\n",
        "\n",
        "These argument conventions are designed to provide systems programmers with\n",
        "total control for memory optimizations while ensuring safe access and timely\n",
        "deallocations—the Mojo compiler ensures that no two variables have mutable\n",
        "access to the same value at the same time, and the lifetime of each value is\n",
        "well-defined to strictly prevent any memory errors such as \"use-after-free\" and\n",
        "\"double-free.\"\n",
        "\n",
        "<div class=\"alert alert-block alert-info alert--secondary\">\n",
        "\n",
        "**Note:** Currently, Mojo always makes a copy when a function returns a value.\n",
        "\n",
        "</div>"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Structures\n",
        "\n",
        "You can build high-level abstractions for types (or \"objects\") in a `struct`. A\n",
        "`struct` in Mojo is similar to a `class` in Python: they both support methods,\n",
        "fields, operator overloading, decorators for metaprogramming, etc. However,\n",
        "Mojo structs are completely static—they are bound at compile-time, so they do\n",
        "not allow dynamic dispatch or any runtime changes to the structure. (Mojo will\n",
        "also support classes in the future.)\n",
        "\n",
        "For example, here's a basic struct:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "metadata": {},
      "outputs": [],
      "source": [
        "struct MyPair:\n",
        "    var first: Int\n",
        "    var second: Int\n",
        "\n",
        "    fn __init__(inout self, first: Int, second: Int):\n",
        "        self.first = first\n",
        "        self.second = second\n",
        "\n",
        "    fn dump(self):\n",
        "        print(self.first, self.second)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "And here's how you can use it:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "2 4\n"
          ]
        }
      ],
      "source": [
        "var mine = MyPair(2, 4)\n",
        "mine.dump()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "If you're familiar with Python, then the `__init__()` method and the `self`\n",
        "argument should be familiar to you. If you're _not_ familiar with Python, then\n",
        "notice that, when we call `dump()`, we don't actually pass a value for the\n",
        "`self` argument. The value for `self` is automatically provided with the\n",
        "current instance of the struct (it's used similar to the `this` name used in\n",
        "some other languages to refer to the current instance of the object/type).\n",
        "\n",
        "For more detail, see the sections of the Mojo Manual about\n",
        "[structs](https://docs.modular.com/mojo/manual/basics/structs.html) and [value\n",
        "lifecycle](https://docs.modular.com/mojo/manual/lifeclcye/)."
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Python integration\n",
        "\n",
        "Although Mojo is still a work in progress and is not a full superset of Python\n",
        "yet, we've built a mechanism to import Python modules as-is, so you can\n",
        "leverage existing Python code right away. Under the hood, this mechanism uses\n",
        "the CPython interpreter to run Python code, and thus it works seamlessly with\n",
        "all Python modules today.\n",
        "\n",
        "For example, here's how you can import and use NumPy (you must have Python\n",
        "`numpy` installed):"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[[ 0  1  2  3  4]\n",
            " [ 5  6  7  8  9]\n",
            " [10 11 12 13 14]]\n",
            "(3, 5)\n"
          ]
        }
      ],
      "source": [
        "from python import Python\n",
        "\n",
        "var np = Python.import_module(\"numpy\")\n",
        "\n",
        "ar = np.arange(15).reshape(3, 5)\n",
        "print(ar)\n",
        "print(ar.shape)"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\n",
        "<div class=\"alert alert-block alert-info alert--secondary\">\n",
        "\n",
        "**Note:** Mojo is not a feature-complete superset of Python yet. So, you can't\n",
        "always copy Python code and run it in Mojo. For more details on our plans,\n",
        "please refer to the [Mojo roadmap and sharp edges](/mojo/roadmap.html).\n",
        "\n",
        "</div>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\n",
        "<div class=\"alert alert-block alert-info alert--warning\">\n",
        "\n",
        "**Caution:** When you install Mojo, the installer searches your system for a\n",
        "version of Python to use with Mojo, and adds the path to the `modular.cfg`\n",
        "config file. If you change your Python version or switch virtual environments,\n",
        "Mojo will then be looking at the wrong Python library, which can cause problems\n",
        "such as errors when you import Python packages (Mojo says only `An error\n",
        "occurred in Python`—this is a separate [known\n",
        "issue](https://github.com/modularml/mojo/issues/536)). The current solution is\n",
        "to override Mojo's path to the Python library, using the `MOJO_PYTHON_LIBRARY`\n",
        "environment variable. For instructions on how to find and set this path, see\n",
        "[this related issue](https://github.com/modularml/mojo/issues/551).\n",
        "\n",
        "</div>"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Next steps\n",
        "\n",
        "We hope this page covered enough of the basics to get you started. It's\n",
        "intentionally brief, so if you want more detail about any of the topics touched\n",
        "upon here, check out the [Mojo\n",
        "programming manual](https://docs.modular.com/mojo/programming-manual.html).\n",
        "\n",
        "- If you want to package your code as a library, read about\n",
        "  [Mojo modules and packages](/mojo/manual/get-started/packages.html).\n",
        "\n",
        "- If you want to explore some Mojo code, check out our\n",
        "  [code examples on GitHub](https://github.com/modularml/mojo/tree/main/examples#mojo-code-examples).\n",
        "\n",
        "- To see all the available Mojo APIs, check out the [Mojo standard library\n",
        "  reference](/mojo/lib.html)."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "<div class=\"alert alert-block alert-info alert--secondary\">\n",
        "\n",
        "**Note:** The Mojo SDK is still in early development. Some things are still\n",
        "rough, but you can expect constant changes and improvements to both the\n",
        "language and tools. Please see the [known\n",
        "issues](/mojo/roadmap.html#mojo-sdk-known-issues) and [report any other\n",
        "issues on GitHub](https://github.com/modularml/mojo/issues/new/choose).\n",
        "\n",
        "</div>"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Mojo",
      "language": "mojo",
      "name": "mojo-jupyter-kernel"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "mojo"
      },
      "file_extension": ".mojo",
      "mimetype": "text/x-mojo",
      "name": "mojo"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 4
}
